// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This file was generated by protoveneer. DO NOT EDIT.

package genai

import (
	"fmt"
	"time"

	pb "cloud.google.com/go/aiplatform/apiv1beta1/aiplatformpb"
	"cloud.google.com/go/civil"
	"google.golang.org/genproto/googleapis/type/date"
	"google.golang.org/protobuf/types/known/structpb"
	"google.golang.org/protobuf/types/known/timestamppb"
)

// Blob contains binary data like images. Use [Text] for text.
type Blob struct {
	// Required. The IANA standard MIME type of the source data.
	MIMEType string
	// Required. Raw bytes.
	Data []byte
}

func (v *Blob) toProto() *pb.Blob {
	if v == nil {
		return nil
	}
	return &pb.Blob{
		MimeType: v.MIMEType,
		Data:     v.Data,
	}
}

func (Blob) fromProto(p *pb.Blob) *Blob {
	if p == nil {
		return nil
	}
	return &Blob{
		MIMEType: p.MimeType,
		Data:     p.Data,
	}
}

// BlockedReason is blocked reason enumeration.
type BlockedReason int32

const (
	// BlockedReasonUnspecified means unspecified blocked reason.
	BlockedReasonUnspecified BlockedReason = 0
	// BlockedReasonSafety means candidates blocked due to safety.
	BlockedReasonSafety BlockedReason = 1
	// BlockedReasonOther means candidates blocked due to other reason.
	BlockedReasonOther BlockedReason = 2
	// BlockedReasonBlocklist means candidates blocked due to the terms which are included from the
	// terminology blocklist.
	BlockedReasonBlocklist BlockedReason = 3
	// BlockedReasonProhibitedContent means candidates blocked due to prohibited content.
	BlockedReasonProhibitedContent BlockedReason = 4
)

var namesForBlockedReason = map[BlockedReason]string{
	BlockedReasonUnspecified:       "BlockedReasonUnspecified",
	BlockedReasonSafety:            "BlockedReasonSafety",
	BlockedReasonOther:             "BlockedReasonOther",
	BlockedReasonBlocklist:         "BlockedReasonBlocklist",
	BlockedReasonProhibitedContent: "BlockedReasonProhibitedContent",
}

func (v BlockedReason) String() string {
	if n, ok := namesForBlockedReason[v]; ok {
		return n
	}
	return fmt.Sprintf("BlockedReason(%d)", v)
}

// CachedContent is a resource used in LLM queries for users to explicitly specify what to cache
// and how to cache.
type CachedContent struct {
	// Expiration time of the cached content.
	//
	// Types that are assignable to Expiration:
	//
	//	*CachedContent_ExpireTime
	//	*CachedContent_Ttl
	Expiration ExpireTimeOrTTL
	// Immutable. Identifier. The server-generated resource name of the cached
	// content Format:
	// projects/{project}/locations/{location}/cachedContents/{cached_content}
	Name string
	// Immutable. The name of the publisher model to use for cached content.
	// Format:
	// projects/{project}/locations/{location}/publishers/{publisher}/models/{model}
	Model string
	// Optional. Input only. Immutable. Developer set system instruction.
	// Currently, text only
	SystemInstruction *Content
	// Optional. Input only. Immutable. The content to cache
	Contents []*Content
	// Optional. Input only. Immutable. A list of `Tools` the model may use to
	// generate the next response
	Tools []*Tool
	// Optional. Input only. Immutable. Tool config. This config is shared for all
	// tools
	ToolConfig *ToolConfig
	// Output only. Creatation time of the cache entry.
	CreateTime time.Time
	// Output only. When the cache entry was last updated in UTC time.
	UpdateTime time.Time
}

func (v *CachedContent) toProto() *pb.CachedContent {
	if v == nil {
		return nil
	}
	p := &pb.CachedContent{
		Name:              v.Name,
		Model:             v.Model,
		SystemInstruction: v.SystemInstruction.toProto(),
		Contents:          pvTransformSlice(v.Contents, (*Content).toProto),
		Tools:             pvTransformSlice(v.Tools, (*Tool).toProto),
		ToolConfig:        v.ToolConfig.toProto(),
		CreateTime:        pvTimeToProto(v.CreateTime),
		UpdateTime:        pvTimeToProto(v.UpdateTime),
	}
	populateCachedContentTo(p, v)
	return p
}

func (CachedContent) fromProto(p *pb.CachedContent) *CachedContent {
	if p == nil {
		return nil
	}
	v := &CachedContent{
		Name:              p.Name,
		Model:             p.Model,
		SystemInstruction: (Content{}).fromProto(p.SystemInstruction),
		Contents:          pvTransformSlice(p.Contents, (Content{}).fromProto),
		Tools:             pvTransformSlice(p.Tools, (Tool{}).fromProto),
		ToolConfig:        (ToolConfig{}).fromProto(p.ToolConfig),
		CreateTime:        pvTimeFromProto(p.CreateTime),
		UpdateTime:        pvTimeFromProto(p.UpdateTime),
	}
	populateCachedContentFrom(v, p)
	return v
}

// Candidate is a response candidate generated from the model.
type Candidate struct {
	// Output only. Index of the candidate.
	Index int32
	// Output only. Content parts of the candidate.
	Content *Content
	// Output only. The reason why the model stopped generating tokens.
	// If empty, the model has not stopped generating the tokens.
	FinishReason FinishReason
	// Output only. List of ratings for the safety of a response candidate.
	//
	// There is at most one rating per category.
	SafetyRatings []*SafetyRating
	// Output only. Describes the reason the mode stopped generating tokens in
	// more detail. This is only filled when `finish_reason` is set.
	FinishMessage string
	// Output only. Source attribution of the generated content.
	CitationMetadata *CitationMetadata
}

func (v *Candidate) toProto() *pb.Candidate {
	if v == nil {
		return nil
	}
	return &pb.Candidate{
		Index:            v.Index,
		Content:          v.Content.toProto(),
		FinishReason:     pb.Candidate_FinishReason(v.FinishReason),
		SafetyRatings:    pvTransformSlice(v.SafetyRatings, (*SafetyRating).toProto),
		FinishMessage:    pvAddrOrNil(v.FinishMessage),
		CitationMetadata: v.CitationMetadata.toProto(),
	}
}

func (Candidate) fromProto(p *pb.Candidate) *Candidate {
	if p == nil {
		return nil
	}
	return &Candidate{
		Index:            p.Index,
		Content:          (Content{}).fromProto(p.Content),
		FinishReason:     FinishReason(p.FinishReason),
		SafetyRatings:    pvTransformSlice(p.SafetyRatings, (SafetyRating{}).fromProto),
		FinishMessage:    pvDerefOrZero(p.FinishMessage),
		CitationMetadata: (CitationMetadata{}).fromProto(p.CitationMetadata),
	}
}

// Citation contains source attributions for content.
type Citation struct {
	// Output only. Start index into the content.
	StartIndex int32
	// Output only. End index into the content.
	EndIndex int32
	// Output only. Url reference of the attribution.
	URI string
	// Output only. Title of the attribution.
	Title string
	// Output only. License of the attribution.
	License string
	// Output only. Publication date of the attribution.
	PublicationDate civil.Date
}

func (v *Citation) toProto() *pb.Citation {
	if v == nil {
		return nil
	}
	return &pb.Citation{
		StartIndex:      v.StartIndex,
		EndIndex:        v.EndIndex,
		Uri:             v.URI,
		Title:           v.Title,
		License:         v.License,
		PublicationDate: pvCivilDateToProto(v.PublicationDate),
	}
}

func (Citation) fromProto(p *pb.Citation) *Citation {
	if p == nil {
		return nil
	}
	return &Citation{
		StartIndex:      p.StartIndex,
		EndIndex:        p.EndIndex,
		URI:             p.Uri,
		Title:           p.Title,
		License:         p.License,
		PublicationDate: pvCivilDateFromProto(p.PublicationDate),
	}
}

// CitationMetadata is a collection of source attributions for a piece of content.
type CitationMetadata struct {
	// Output only. List of citations.
	Citations []*Citation
}

func (v *CitationMetadata) toProto() *pb.CitationMetadata {
	if v == nil {
		return nil
	}
	return &pb.CitationMetadata{
		Citations: pvTransformSlice(v.Citations, (*Citation).toProto),
	}
}

func (CitationMetadata) fromProto(p *pb.CitationMetadata) *CitationMetadata {
	if p == nil {
		return nil
	}
	return &CitationMetadata{
		Citations: pvTransformSlice(p.Citations, (Citation{}).fromProto),
	}
}

// Content is the base structured datatype containing multi-part content of a message.
//
// A `Content` includes a `role` field designating the producer of the `Content`
// and a `parts` field containing multi-part data that contains the content of
// the message turn.
type Content struct {
	// Optional. The producer of the content. Must be either 'user' or 'model'.
	//
	// Useful to set for multi-turn conversations, otherwise can be left blank
	// or unset.
	Role string
	// Required. Ordered `Parts` that constitute a single message. Parts may have
	// different IANA MIME types.
	Parts []Part
}

func (v *Content) toProto() *pb.Content {
	if v == nil {
		return nil
	}
	return &pb.Content{
		Role:  v.Role,
		Parts: pvTransformSlice(v.Parts, partToProto),
	}
}

func (Content) fromProto(p *pb.Content) *Content {
	if p == nil {
		return nil
	}
	return &Content{
		Role:  p.Role,
		Parts: pvTransformSlice(p.Parts, partFromProto),
	}
}

// CountTokensResponse is response message for
// [PredictionService.CountTokens][google.cloud.aiplatform.v1beta1.PredictionService.CountTokens].
type CountTokensResponse struct {
	// The total number of tokens counted across all instances from the request.
	TotalTokens int32
	// The total number of billable characters counted across all instances from
	// the request.
	TotalBillableCharacters int32
}

func (v *CountTokensResponse) toProto() *pb.CountTokensResponse {
	if v == nil {
		return nil
	}
	return &pb.CountTokensResponse{
		TotalTokens:             v.TotalTokens,
		TotalBillableCharacters: v.TotalBillableCharacters,
	}
}

func (CountTokensResponse) fromProto(p *pb.CountTokensResponse) *CountTokensResponse {
	if p == nil {
		return nil
	}
	return &CountTokensResponse{
		TotalTokens:             p.TotalTokens,
		TotalBillableCharacters: p.TotalBillableCharacters,
	}
}

// FileData is URI based data.
type FileData struct {
	// Required. The IANA standard MIME type of the source data.
	MIMEType string
	// Required. URI.
	FileURI string
}

func (v *FileData) toProto() *pb.FileData {
	if v == nil {
		return nil
	}
	return &pb.FileData{
		MimeType: v.MIMEType,
		FileUri:  v.FileURI,
	}
}

func (FileData) fromProto(p *pb.FileData) *FileData {
	if p == nil {
		return nil
	}
	return &FileData{
		MIMEType: p.MimeType,
		FileURI:  p.FileUri,
	}
}

// FinishReason is the reason why the model stopped generating tokens.
// If empty, the model has not stopped generating the tokens.
type FinishReason int32

const (
	// FinishReasonUnspecified means the finish reason is unspecified.
	FinishReasonUnspecified FinishReason = 0
	// FinishReasonStop means natural stop point of the model or provided stop sequence.
	FinishReasonStop FinishReason = 1
	// FinishReasonMaxTokens means the maximum number of tokens as specified in the request was reached.
	FinishReasonMaxTokens FinishReason = 2
	// FinishReasonSafety means the token generation was stopped as the response was flagged for safety
	// reasons. NOTE: When streaming the Candidate.content will be empty if
	// content filters blocked the output.
	FinishReasonSafety FinishReason = 3
	// FinishReasonRecitation means the token generation was stopped as the response was flagged for
	// unauthorized citations.
	FinishReasonRecitation FinishReason = 4
	// FinishReasonOther means all other reasons that stopped the token generation
	FinishReasonOther FinishReason = 5
	// FinishReasonBlocklist means the token generation was stopped as the response was flagged for the
	// terms which are included from the terminology blocklist.
	FinishReasonBlocklist FinishReason = 6
	// FinishReasonProhibitedContent means the token generation was stopped as the response was flagged for
	// the prohibited contents.
	FinishReasonProhibitedContent FinishReason = 7
	// FinishReasonSpii means the token generation was stopped as the response was flagged for
	// Sensitive Personally Identifiable Information (SPII) contents.
	FinishReasonSpii FinishReason = 8
	// FinishReasonMalformedFunctionCall means the function call generated by the model is invalid.
	FinishReasonMalformedFunctionCall FinishReason = 9
)

var namesForFinishReason = map[FinishReason]string{
	FinishReasonUnspecified:           "FinishReasonUnspecified",
	FinishReasonStop:                  "FinishReasonStop",
	FinishReasonMaxTokens:             "FinishReasonMaxTokens",
	FinishReasonSafety:                "FinishReasonSafety",
	FinishReasonRecitation:            "FinishReasonRecitation",
	FinishReasonOther:                 "FinishReasonOther",
	FinishReasonBlocklist:             "FinishReasonBlocklist",
	FinishReasonProhibitedContent:     "FinishReasonProhibitedContent",
	FinishReasonSpii:                  "FinishReasonSpii",
	FinishReasonMalformedFunctionCall: "FinishReasonMalformedFunctionCall",
}

func (v FinishReason) String() string {
	if n, ok := namesForFinishReason[v]; ok {
		return n
	}
	return fmt.Sprintf("FinishReason(%d)", v)
}

// FunctionCall is a predicted [FunctionCall] returned from the model that contains a string
// representing the [FunctionDeclaration.name] and a structured JSON object
// containing the parameters and their values.
type FunctionCall struct {
	// Required. The name of the function to call.
	// Matches [FunctionDeclaration.name].
	Name string
	// Optional. Required. The function parameters and values in JSON object
	// format. See [FunctionDeclaration.parameters] for parameter details.
	Args map[string]any
}

func (v *FunctionCall) toProto() *pb.FunctionCall {
	if v == nil {
		return nil
	}
	return &pb.FunctionCall{
		Name: v.Name,
		Args: pvMapToStructPB(v.Args),
	}
}

func (FunctionCall) fromProto(p *pb.FunctionCall) *FunctionCall {
	if p == nil {
		return nil
	}
	return &FunctionCall{
		Name: p.Name,
		Args: pvMapFromStructPB(p.Args),
	}
}

// FunctionCallingConfig holds configuration for function calling.
type FunctionCallingConfig struct {
	// Optional. Function calling mode.
	Mode FunctionCallingMode
	// Optional. Function names to call. Only set when the Mode is ANY. Function
	// names should match [FunctionDeclaration.name]. With mode set to ANY, model
	// will predict a function call from the set of function names provided.
	AllowedFunctionNames []string
}

func (v *FunctionCallingConfig) toProto() *pb.FunctionCallingConfig {
	if v == nil {
		return nil
	}
	return &pb.FunctionCallingConfig{
		Mode:                 pb.FunctionCallingConfig_Mode(v.Mode),
		AllowedFunctionNames: v.AllowedFunctionNames,
	}
}

func (FunctionCallingConfig) fromProto(p *pb.FunctionCallingConfig) *FunctionCallingConfig {
	if p == nil {
		return nil
	}
	return &FunctionCallingConfig{
		Mode:                 FunctionCallingMode(p.Mode),
		AllowedFunctionNames: p.AllowedFunctionNames,
	}
}

// FunctionCallingMode is function calling mode.
type FunctionCallingMode int32

const (
	// FunctionCallingUnspecified means unspecified function calling mode. This value should not be used.
	FunctionCallingUnspecified FunctionCallingMode = 0
	// FunctionCallingAuto means default model behavior, model decides to predict either a function call
	// or a natural language repspose.
	FunctionCallingAuto FunctionCallingMode = 1
	// FunctionCallingAny means model is constrained to always predicting a function call only.
	// If "allowed_function_names" are set, the predicted function call will be
	// limited to any one of "allowed_function_names", else the predicted
	// function call will be any one of the provided "function_declarations".
	FunctionCallingAny FunctionCallingMode = 2
	// FunctionCallingNone means model will not predict any function call. Model behavior is same as when
	// not passing any function declarations.
	FunctionCallingNone FunctionCallingMode = 3
)

var namesForFunctionCallingMode = map[FunctionCallingMode]string{
	FunctionCallingUnspecified: "FunctionCallingUnspecified",
	FunctionCallingAuto:        "FunctionCallingAuto",
	FunctionCallingAny:         "FunctionCallingAny",
	FunctionCallingNone:        "FunctionCallingNone",
}

func (v FunctionCallingMode) String() string {
	if n, ok := namesForFunctionCallingMode[v]; ok {
		return n
	}
	return fmt.Sprintf("FunctionCallingMode(%d)", v)
}

// FunctionDeclaration is structured representation of a function declaration as defined by the
// [OpenAPI 3.0 specification](https://spec.openapis.org/oas/v3.0.3). Included
// in this declaration are the function name and parameters. This
// FunctionDeclaration is a representation of a block of code that can be used
// as a `Tool` by the model and executed by the client.
type FunctionDeclaration struct {
	// Required. The name of the function to call.
	// Must start with a letter or an underscore.
	// Must be a-z, A-Z, 0-9, or contain underscores, dots and dashes, with a
	// maximum length of 64.
	Name string
	// Optional. Description and purpose of the function.
	// Model uses it to decide how and whether to call the function.
	Description string
	// Optional. Describes the parameters to this function in JSON Schema Object
	// format. Reflects the Open API 3.03 Parameter Object. string Key: the name
	// of the parameter. Parameter names are case sensitive. Schema Value: the
	// Schema defining the type used for the parameter. For function with no
	// parameters, this can be left unset. Parameter names must start with a
	// letter or an underscore and must only contain chars a-z, A-Z, 0-9, or
	// underscores with a maximum length of 64. Example with 1 required and 1
	// optional parameter: type: OBJECT properties:
	//
	//	param1:
	//	  type: STRING
	//	param2:
	//	  type: INTEGER
	//
	// required:
	//   - param1
	Parameters *Schema
	// Optional. Describes the output from this function in JSON Schema format.
	// Reflects the Open API 3.03 Response Object. The Schema defines the type
	// used for the response value of the function.
	Response *Schema
}

func (v *FunctionDeclaration) toProto() *pb.FunctionDeclaration {
	if v == nil {
		return nil
	}
	return &pb.FunctionDeclaration{
		Name:        v.Name,
		Description: v.Description,
		Parameters:  v.Parameters.toProto(),
		Response:    v.Response.toProto(),
	}
}

func (FunctionDeclaration) fromProto(p *pb.FunctionDeclaration) *FunctionDeclaration {
	if p == nil {
		return nil
	}
	return &FunctionDeclaration{
		Name:        p.Name,
		Description: p.Description,
		Parameters:  (Schema{}).fromProto(p.Parameters),
		Response:    (Schema{}).fromProto(p.Response),
	}
}

// FunctionResponse is the result output from a [FunctionCall] that contains a string representing
// the [FunctionDeclaration.name] and a structured JSON object containing any
// output from the function is used as context to the model. This should contain
// the result of a [FunctionCall] made based on model prediction.
type FunctionResponse struct {
	// Required. The name of the function to call.
	// Matches [FunctionDeclaration.name] and [FunctionCall.name].
	Name string
	// Required. The function response in JSON object format.
	Response map[string]any
}

func (v *FunctionResponse) toProto() *pb.FunctionResponse {
	if v == nil {
		return nil
	}
	return &pb.FunctionResponse{
		Name:     v.Name,
		Response: pvMapToStructPB(v.Response),
	}
}

func (FunctionResponse) fromProto(p *pb.FunctionResponse) *FunctionResponse {
	if p == nil {
		return nil
	}
	return &FunctionResponse{
		Name:     p.Name,
		Response: pvMapFromStructPB(p.Response),
	}
}

// GenerateContentResponse is the response from a GenerateContent or GenerateContentStream call.
type GenerateContentResponse struct {
	// Output only. Generated candidates.
	Candidates []*Candidate
	// Output only. Content filter results for a prompt sent in the request.
	// Note: Sent only in the first stream chunk.
	// Only happens when no candidates were generated due to content violations.
	PromptFeedback *PromptFeedback
	// Usage metadata about the response(s).
	UsageMetadata *UsageMetadata
}

func (v *GenerateContentResponse) toProto() *pb.GenerateContentResponse {
	if v == nil {
		return nil
	}
	return &pb.GenerateContentResponse{
		Candidates:     pvTransformSlice(v.Candidates, (*Candidate).toProto),
		PromptFeedback: v.PromptFeedback.toProto(),
		UsageMetadata:  v.UsageMetadata.toProto(),
	}
}

func (GenerateContentResponse) fromProto(p *pb.GenerateContentResponse) *GenerateContentResponse {
	if p == nil {
		return nil
	}
	return &GenerateContentResponse{
		Candidates:     pvTransformSlice(p.Candidates, (Candidate{}).fromProto),
		PromptFeedback: (PromptFeedback{}).fromProto(p.PromptFeedback),
		UsageMetadata:  (UsageMetadata{}).fromProto(p.UsageMetadata),
	}
}

// GenerationConfig is generation config.
type GenerationConfig struct {
	// Optional. Controls the randomness of predictions.
	Temperature *float32
	// Optional. If specified, nucleus sampling will be used.
	TopP *float32
	// Optional. If specified, top-k sampling will be used.
	TopK *int32
	// Optional. Number of candidates to generate.
	CandidateCount *int32
	// Optional. The maximum number of output tokens to generate per message.
	MaxOutputTokens *int32
	// Optional. Stop sequences.
	StopSequences []string
	// Optional. Positive penalties.
	PresencePenalty *float32
	// Optional. Frequency penalties.
	FrequencyPenalty *float32
	// Optional. Output response mimetype of the generated candidate text.
	// Supported mimetype:
	// - `text/plain`: (default) Text output.
	// - `application/json`: JSON response in the candidates.
	// The model needs to be prompted to output the appropriate response type,
	// otherwise the behavior is undefined.
	// This is a preview feature.
	ResponseMIMEType string
	// Optional. The `Schema` object allows the definition of input and output
	// data types. These types can be objects, but also primitives and arrays.
	// Represents a select subset of an [OpenAPI 3.0 schema
	// object](https://spec.openapis.org/oas/v3.0.3#schema).
	// If set, a compatible response_mime_type must also be set.
	// Compatible mimetypes:
	// `application/json`: Schema for JSON response.
	ResponseSchema *Schema
}

func (v *GenerationConfig) toProto() *pb.GenerationConfig {
	if v == nil {
		return nil
	}
	return &pb.GenerationConfig{
		Temperature:      v.Temperature,
		TopP:             v.TopP,
		TopK:             int32pToFloat32p(v.TopK),
		CandidateCount:   v.CandidateCount,
		MaxOutputTokens:  v.MaxOutputTokens,
		StopSequences:    v.StopSequences,
		PresencePenalty:  v.PresencePenalty,
		FrequencyPenalty: v.FrequencyPenalty,
		ResponseMimeType: v.ResponseMIMEType,
		ResponseSchema:   v.ResponseSchema.toProto(),
	}
}

func (GenerationConfig) fromProto(p *pb.GenerationConfig) *GenerationConfig {
	if p == nil {
		return nil
	}
	return &GenerationConfig{
		Temperature:      p.Temperature,
		TopP:             p.TopP,
		TopK:             float32pToInt32p(p.TopK),
		CandidateCount:   p.CandidateCount,
		MaxOutputTokens:  p.MaxOutputTokens,
		StopSequences:    p.StopSequences,
		PresencePenalty:  p.PresencePenalty,
		FrequencyPenalty: p.FrequencyPenalty,
		ResponseMIMEType: p.ResponseMimeType,
		ResponseSchema:   (Schema{}).fromProto(p.ResponseSchema),
	}
}

// HarmBlockMethod determines how harm blocking is done.
type HarmBlockMethod int32

const (
	// HarmBlockMethodUnspecified means the harm block method is unspecified.
	HarmBlockMethodUnspecified HarmBlockMethod = 0
	// HarmBlockMethodSeverity means the harm block method uses both probability and severity scores.
	HarmBlockMethodSeverity HarmBlockMethod = 1
	// HarmBlockMethodProbability means the harm block method uses the probability score.
	HarmBlockMethodProbability HarmBlockMethod = 2
)

var namesForHarmBlockMethod = map[HarmBlockMethod]string{
	HarmBlockMethodUnspecified: "HarmBlockMethodUnspecified",
	HarmBlockMethodSeverity:    "HarmBlockMethodSeverity",
	HarmBlockMethodProbability: "HarmBlockMethodProbability",
}

func (v HarmBlockMethod) String() string {
	if n, ok := namesForHarmBlockMethod[v]; ok {
		return n
	}
	return fmt.Sprintf("HarmBlockMethod(%d)", v)
}

// HarmBlockThreshold specifies probability based thresholds levels for blocking.
type HarmBlockThreshold int32

const (
	// HarmBlockUnspecified means unspecified harm block threshold.
	HarmBlockUnspecified HarmBlockThreshold = 0
	// HarmBlockLowAndAbove means block low threshold and above (i.e. block more).
	HarmBlockLowAndAbove HarmBlockThreshold = 1
	// HarmBlockMediumAndAbove means block medium threshold and above.
	HarmBlockMediumAndAbove HarmBlockThreshold = 2
	// HarmBlockOnlyHigh means block only high threshold (i.e. block less).
	HarmBlockOnlyHigh HarmBlockThreshold = 3
	// HarmBlockNone means block none.
	HarmBlockNone HarmBlockThreshold = 4
)

var namesForHarmBlockThreshold = map[HarmBlockThreshold]string{
	HarmBlockUnspecified:    "HarmBlockUnspecified",
	HarmBlockLowAndAbove:    "HarmBlockLowAndAbove",
	HarmBlockMediumAndAbove: "HarmBlockMediumAndAbove",
	HarmBlockOnlyHigh:       "HarmBlockOnlyHigh",
	HarmBlockNone:           "HarmBlockNone",
}

func (v HarmBlockThreshold) String() string {
	if n, ok := namesForHarmBlockThreshold[v]; ok {
		return n
	}
	return fmt.Sprintf("HarmBlockThreshold(%d)", v)
}

// HarmCategory specifies harm categories that will block the content.
type HarmCategory int32

const (
	// HarmCategoryUnspecified means the harm category is unspecified.
	HarmCategoryUnspecified HarmCategory = 0
	// HarmCategoryHateSpeech means the harm category is hate speech.
	HarmCategoryHateSpeech HarmCategory = 1
	// HarmCategoryDangerousContent means the harm category is dangerous content.
	HarmCategoryDangerousContent HarmCategory = 2
	// HarmCategoryHarassment means the harm category is harassment.
	HarmCategoryHarassment HarmCategory = 3
	// HarmCategorySexuallyExplicit means the harm category is sexually explicit content.
	HarmCategorySexuallyExplicit HarmCategory = 4
)

var namesForHarmCategory = map[HarmCategory]string{
	HarmCategoryUnspecified:      "HarmCategoryUnspecified",
	HarmCategoryHateSpeech:       "HarmCategoryHateSpeech",
	HarmCategoryDangerousContent: "HarmCategoryDangerousContent",
	HarmCategoryHarassment:       "HarmCategoryHarassment",
	HarmCategorySexuallyExplicit: "HarmCategorySexuallyExplicit",
}

func (v HarmCategory) String() string {
	if n, ok := namesForHarmCategory[v]; ok {
		return n
	}
	return fmt.Sprintf("HarmCategory(%d)", v)
}

// HarmProbability specifies harm probability levels in the content.
type HarmProbability int32

const (
	// HarmProbabilityUnspecified means harm probability unspecified.
	HarmProbabilityUnspecified HarmProbability = 0
	// HarmProbabilityNegligible means negligible level of harm.
	HarmProbabilityNegligible HarmProbability = 1
	// HarmProbabilityLow means low level of harm.
	HarmProbabilityLow HarmProbability = 2
	// HarmProbabilityMedium means medium level of harm.
	HarmProbabilityMedium HarmProbability = 3
	// HarmProbabilityHigh means high level of harm.
	HarmProbabilityHigh HarmProbability = 4
)

var namesForHarmProbability = map[HarmProbability]string{
	HarmProbabilityUnspecified: "HarmProbabilityUnspecified",
	HarmProbabilityNegligible:  "HarmProbabilityNegligible",
	HarmProbabilityLow:         "HarmProbabilityLow",
	HarmProbabilityMedium:      "HarmProbabilityMedium",
	HarmProbabilityHigh:        "HarmProbabilityHigh",
}

func (v HarmProbability) String() string {
	if n, ok := namesForHarmProbability[v]; ok {
		return n
	}
	return fmt.Sprintf("HarmProbability(%d)", v)
}

// HarmSeverity specifies harm severity levels.
type HarmSeverity int32

const (
	// HarmSeverityUnspecified means harm severity unspecified.
	HarmSeverityUnspecified HarmSeverity = 0
	// HarmSeverityNegligible means negligible level of harm severity.
	HarmSeverityNegligible HarmSeverity = 1
	// HarmSeverityLow means low level of harm severity.
	HarmSeverityLow HarmSeverity = 2
	// HarmSeverityMedium means medium level of harm severity.
	HarmSeverityMedium HarmSeverity = 3
	// HarmSeverityHigh means high level of harm severity.
	HarmSeverityHigh HarmSeverity = 4
)

var namesForHarmSeverity = map[HarmSeverity]string{
	HarmSeverityUnspecified: "HarmSeverityUnspecified",
	HarmSeverityNegligible:  "HarmSeverityNegligible",
	HarmSeverityLow:         "HarmSeverityLow",
	HarmSeverityMedium:      "HarmSeverityMedium",
	HarmSeverityHigh:        "HarmSeverityHigh",
}

func (v HarmSeverity) String() string {
	if n, ok := namesForHarmSeverity[v]; ok {
		return n
	}
	return fmt.Sprintf("HarmSeverity(%d)", v)
}

// PromptFeedback contains content filter results for a prompt sent in the request.
type PromptFeedback struct {
	// Output only. Blocked reason.
	BlockReason BlockedReason
	// Output only. Safety ratings.
	SafetyRatings []*SafetyRating
	// Output only. A readable block reason message.
	BlockReasonMessage string
}

func (v *PromptFeedback) toProto() *pb.GenerateContentResponse_PromptFeedback {
	if v == nil {
		return nil
	}
	return &pb.GenerateContentResponse_PromptFeedback{
		BlockReason:        pb.GenerateContentResponse_PromptFeedback_BlockedReason(v.BlockReason),
		SafetyRatings:      pvTransformSlice(v.SafetyRatings, (*SafetyRating).toProto),
		BlockReasonMessage: v.BlockReasonMessage,
	}
}

func (PromptFeedback) fromProto(p *pb.GenerateContentResponse_PromptFeedback) *PromptFeedback {
	if p == nil {
		return nil
	}
	return &PromptFeedback{
		BlockReason:        BlockedReason(p.BlockReason),
		SafetyRatings:      pvTransformSlice(p.SafetyRatings, (SafetyRating{}).fromProto),
		BlockReasonMessage: p.BlockReasonMessage,
	}
}

// SafetyRating is the safety rating corresponding to the generated content.
type SafetyRating struct {
	// Output only. Harm category.
	Category HarmCategory
	// Output only. Harm probability levels in the content.
	Probability HarmProbability
	// Output only. Harm probability score.
	ProbabilityScore float32
	// Output only. Harm severity levels in the content.
	Severity HarmSeverity
	// Output only. Harm severity score.
	SeverityScore float32
	// Output only. Indicates whether the content was filtered out because of this
	// rating.
	Blocked bool
}

func (v *SafetyRating) toProto() *pb.SafetyRating {
	if v == nil {
		return nil
	}
	return &pb.SafetyRating{
		Category:         pb.HarmCategory(v.Category),
		Probability:      pb.SafetyRating_HarmProbability(v.Probability),
		ProbabilityScore: v.ProbabilityScore,
		Severity:         pb.SafetyRating_HarmSeverity(v.Severity),
		SeverityScore:    v.SeverityScore,
		Blocked:          v.Blocked,
	}
}

func (SafetyRating) fromProto(p *pb.SafetyRating) *SafetyRating {
	if p == nil {
		return nil
	}
	return &SafetyRating{
		Category:         HarmCategory(p.Category),
		Probability:      HarmProbability(p.Probability),
		ProbabilityScore: p.ProbabilityScore,
		Severity:         HarmSeverity(p.Severity),
		SeverityScore:    p.SeverityScore,
		Blocked:          p.Blocked,
	}
}

// SafetySetting is safety settings.
type SafetySetting struct {
	// Required. Harm category.
	Category HarmCategory
	// Required. The harm block threshold.
	Threshold HarmBlockThreshold
	// Optional. Specify if the threshold is used for probability or severity
	// score. If not specified, the threshold is used for probability score.
	Method HarmBlockMethod
}

func (v *SafetySetting) toProto() *pb.SafetySetting {
	if v == nil {
		return nil
	}
	return &pb.SafetySetting{
		Category:  pb.HarmCategory(v.Category),
		Threshold: pb.SafetySetting_HarmBlockThreshold(v.Threshold),
		Method:    pb.SafetySetting_HarmBlockMethod(v.Method),
	}
}

func (SafetySetting) fromProto(p *pb.SafetySetting) *SafetySetting {
	if p == nil {
		return nil
	}
	return &SafetySetting{
		Category:  HarmCategory(p.Category),
		Threshold: HarmBlockThreshold(p.Threshold),
		Method:    HarmBlockMethod(p.Method),
	}
}

// Schema is used to define the format of input/output data. Represents a select
// subset of an [OpenAPI 3.0 schema
// object](https://spec.openapis.org/oas/v3.0.3#schema). More fields may be
// added in the future as needed.
type Schema struct {
	// Optional. The type of the data.
	Type Type
	// Optional. The format of the data.
	// Supported formats:
	//
	//	for NUMBER type: "float", "double"
	//	for INTEGER type: "int32", "int64"
	//	for STRING type: "email", "byte", etc
	Format string
	// Optional. The title of the Schema.
	Title string
	// Optional. The description of the data.
	Description string
	// Optional. Indicates if the value may be null.
	Nullable bool
	// Optional. SCHEMA FIELDS FOR TYPE ARRAY
	// Schema of the elements of Type.ARRAY.
	Items *Schema
	// Optional. Minimum number of the elements for Type.ARRAY.
	MinItems int64
	// Optional. Maximum number of the elements for Type.ARRAY.
	MaxItems int64
	// Optional. Possible values of the element of Type.STRING with enum format.
	// For example we can define an Enum Direction as :
	// {type:STRING, format:enum, enum:["EAST", NORTH", "SOUTH", "WEST"]}
	Enum []string
	// Optional. SCHEMA FIELDS FOR TYPE OBJECT
	// Properties of Type.OBJECT.
	Properties map[string]*Schema
	// Optional. Required properties of Type.OBJECT.
	Required []string
	// Optional. Minimum number of the properties for Type.OBJECT.
	MinProperties int64
	// Optional. Maximum number of the properties for Type.OBJECT.
	MaxProperties int64
	// Optional. SCHEMA FIELDS FOR TYPE INTEGER and NUMBER
	// Minimum value of the Type.INTEGER and Type.NUMBER
	Minimum float64
	// Optional. Maximum value of the Type.INTEGER and Type.NUMBER
	Maximum float64
	// Optional. SCHEMA FIELDS FOR TYPE STRING
	// Minimum length of the Type.STRING
	MinLength int64
	// Optional. Maximum length of the Type.STRING
	MaxLength int64
	// Optional. Pattern of the Type.STRING to restrict a string to a regular
	// expression.
	Pattern string
}

func (v *Schema) toProto() *pb.Schema {
	if v == nil {
		return nil
	}
	return &pb.Schema{
		Type:          pb.Type(v.Type),
		Format:        v.Format,
		Title:         v.Title,
		Description:   v.Description,
		Nullable:      v.Nullable,
		Items:         v.Items.toProto(),
		MinItems:      v.MinItems,
		MaxItems:      v.MaxItems,
		Enum:          v.Enum,
		Properties:    pvTransformMapValues(v.Properties, (*Schema).toProto),
		Required:      v.Required,
		MinProperties: v.MinProperties,
		MaxProperties: v.MaxProperties,
		Minimum:       v.Minimum,
		Maximum:       v.Maximum,
		MinLength:     v.MinLength,
		MaxLength:     v.MaxLength,
		Pattern:       v.Pattern,
	}
}

func (Schema) fromProto(p *pb.Schema) *Schema {
	if p == nil {
		return nil
	}
	return &Schema{
		Type:          Type(p.Type),
		Format:        p.Format,
		Title:         p.Title,
		Description:   p.Description,
		Nullable:      p.Nullable,
		Items:         (Schema{}).fromProto(p.Items),
		MinItems:      p.MinItems,
		MaxItems:      p.MaxItems,
		Enum:          p.Enum,
		Properties:    pvTransformMapValues(p.Properties, (Schema{}).fromProto),
		Required:      p.Required,
		MinProperties: p.MinProperties,
		MaxProperties: p.MaxProperties,
		Minimum:       p.Minimum,
		Maximum:       p.Maximum,
		MinLength:     p.MinLength,
		MaxLength:     p.MaxLength,
		Pattern:       p.Pattern,
	}
}

// Tool details that the model may use to generate response.
//
// A `Tool` is a piece of code that enables the system to interact with
// external systems to perform an action, or set of actions, outside of
// knowledge and scope of the model. A Tool object should contain exactly
// one type of Tool (e.g FunctionDeclaration, Retrieval or
// GoogleSearchRetrieval).
type Tool struct {
	// Optional. Function tool type.
	// One or more function declarations to be passed to the model along with the
	// current user query. Model may decide to call a subset of these functions
	// by populating [FunctionCall][content.part.function_call] in the response.
	// User should provide a [FunctionResponse][content.part.function_response]
	// for each function call in the next turn. Based on the function responses,
	// Model will generate the final response back to the user.
	// Maximum 64 function declarations can be provided.
	FunctionDeclarations []*FunctionDeclaration
}

func (v *Tool) toProto() *pb.Tool {
	if v == nil {
		return nil
	}
	return &pb.Tool{
		FunctionDeclarations: pvTransformSlice(v.FunctionDeclarations, (*FunctionDeclaration).toProto),
	}
}

func (Tool) fromProto(p *pb.Tool) *Tool {
	if p == nil {
		return nil
	}
	return &Tool{
		FunctionDeclarations: pvTransformSlice(p.FunctionDeclarations, (FunctionDeclaration{}).fromProto),
	}
}

// ToolConfig configures tools.
type ToolConfig struct {
	// Optional. Function calling config.
	FunctionCallingConfig *FunctionCallingConfig
}

func (v *ToolConfig) toProto() *pb.ToolConfig {
	if v == nil {
		return nil
	}
	return &pb.ToolConfig{
		FunctionCallingConfig: v.FunctionCallingConfig.toProto(),
	}
}

func (ToolConfig) fromProto(p *pb.ToolConfig) *ToolConfig {
	if p == nil {
		return nil
	}
	return &ToolConfig{
		FunctionCallingConfig: (FunctionCallingConfig{}).fromProto(p.FunctionCallingConfig),
	}
}

// Type contains the list of OpenAPI data types as defined by
// https://swagger.io/docs/specification/data-models/data-types/
type Type int32

const (
	// TypeUnspecified means not specified, should not be used.
	TypeUnspecified Type = 0
	// TypeString means openAPI string type
	TypeString Type = 1
	// TypeNumber means openAPI number type
	TypeNumber Type = 2
	// TypeInteger means openAPI integer type
	TypeInteger Type = 3
	// TypeBoolean means openAPI boolean type
	TypeBoolean Type = 4
	// TypeArray means openAPI array type
	TypeArray Type = 5
	// TypeObject means openAPI object type
	TypeObject Type = 6
)

var namesForType = map[Type]string{
	TypeUnspecified: "TypeUnspecified",
	TypeString:      "TypeString",
	TypeNumber:      "TypeNumber",
	TypeInteger:     "TypeInteger",
	TypeBoolean:     "TypeBoolean",
	TypeArray:       "TypeArray",
	TypeObject:      "TypeObject",
}

func (v Type) String() string {
	if n, ok := namesForType[v]; ok {
		return n
	}
	return fmt.Sprintf("Type(%d)", v)
}

// UsageMetadata is usage metadata about response(s).
type UsageMetadata struct {
	// Number of tokens in the request.
	PromptTokenCount int32
	// Number of tokens in the response(s).
	CandidatesTokenCount int32
	TotalTokenCount      int32
}

func (v *UsageMetadata) toProto() *pb.GenerateContentResponse_UsageMetadata {
	if v == nil {
		return nil
	}
	return &pb.GenerateContentResponse_UsageMetadata{
		PromptTokenCount:     v.PromptTokenCount,
		CandidatesTokenCount: v.CandidatesTokenCount,
		TotalTokenCount:      v.TotalTokenCount,
	}
}

func (UsageMetadata) fromProto(p *pb.GenerateContentResponse_UsageMetadata) *UsageMetadata {
	if p == nil {
		return nil
	}
	return &UsageMetadata{
		PromptTokenCount:     p.PromptTokenCount,
		CandidatesTokenCount: p.CandidatesTokenCount,
		TotalTokenCount:      p.TotalTokenCount,
	}
}

func pvTransformSlice[From, To any](from []From, f func(From) To) []To {
	if from == nil {
		return nil
	}
	to := make([]To, len(from))
	for i, e := range from {
		to[i] = f(e)
	}
	return to
}

func pvTransformMapValues[K comparable, VFrom, VTo any](from map[K]VFrom, f func(VFrom) VTo) map[K]VTo {
	if from == nil {
		return nil
	}
	to := map[K]VTo{}
	for k, v := range from {
		to[k] = f(v)
	}
	return to
}

func pvAddrOrNil[T comparable](x T) *T {
	var z T
	if x == z {
		return nil
	}
	return &x
}

func pvDerefOrZero[T any](x *T) T {
	if x == nil {
		var z T
		return z
	}
	return *x
}

func pvCivilDateToProto(d civil.Date) *date.Date {
	return &date.Date{
		Year:  int32(d.Year),
		Month: int32(d.Month),
		Day:   int32(d.Day),
	}
}

func pvCivilDateFromProto(p *date.Date) civil.Date {
	if p == nil {
		return civil.Date{}
	}
	return civil.Date{
		Year:  int(p.Year),
		Month: time.Month(p.Month),
		Day:   int(p.Day),
	}
}

func pvMapToStructPB(m map[string]any) *structpb.Struct {
	if m == nil {
		return nil
	}
	s, err := structpb.NewStruct(m)
	if err != nil {
		panic(pvPanic(fmt.Errorf("pvMapToStructPB: %w", err)))
	}
	return s
}

func pvMapFromStructPB(p *structpb.Struct) map[string]any {
	if p == nil {
		return nil
	}
	return p.AsMap()
}

func pvTimeToProto(t time.Time) *timestamppb.Timestamp {
	if t.IsZero() {
		return nil
	}
	return timestamppb.New(t)
}

func pvTimeFromProto(ts *timestamppb.Timestamp) time.Time {
	if ts == nil {
		return time.Time{}
	}
	return ts.AsTime()
}

type pvPanic error
